package vip.aster.framework.mybatis.config;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.type.LocalDateTimeTypeHandler;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import vip.aster.framework.mybatis.handler.OracleLocalDateTimeTypeHandler;
import vip.aster.framework.mybatis.handler.MybatisPlusMetaObjectHandler;
import vip.aster.framework.mybatis.interceptor.AsterDataPermissionInterceptor;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * mybatis-plus配置
 *
 * @author Aster
 * @since 2023/11/24 15:31
 */
@Slf4j
@Configuration
public class MybatisPlusConfig {

    @Value("${data-permission.enabled}")
    private boolean enableDataPermission;
    @Resource
    private DataSource dataSource;
    // 缓存数据库类型，避免重复查询
    private static final Map<String, String> DB_TYPE_CACHE = new ConcurrentHashMap<>();

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        if (enableDataPermission) {
            // 数据权限插件
            interceptor.addInnerInterceptor(asterDataPermissionInterceptor());
        }
        // 分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        // 乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        // 防全表更新与删除
        interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());

        return interceptor;
    }

    @Bean
    public MybatisPlusMetaObjectHandler mybatisPlusMetaObjectHandler() {
        return new MybatisPlusMetaObjectHandler();
    }

    @Bean
    public AsterDataPermissionInterceptor asterDataPermissionInterceptor() {
        return new AsterDataPermissionInterceptor();
    }

    @Bean
    public LocalDateTimeTypeHandler asterLocalDateTimeTypehandler() throws SQLException {
        try (Connection connection = dataSource.getConnection()) { // 使用 try-with-resources 确保资源释放
            String dbType = getDatabaseType(connection);
            if (StrUtil.equalsAny(dbType, "Oracle")) {
                return new OracleLocalDateTimeTypeHandler();
            }
            return new LocalDateTimeTypeHandler();
        } catch (SQLException e) {
            // 记录异常日志并抛出自定义异常
            log.error("Failed to determine database type: " + e.getMessage());
            throw new RuntimeException("Database connection error", e);
        }
    }

    /**
     * 获取数据库类型
     *
     * @param connection 数据库连接
     * @return 数据库类型
     * @throws SQLException SQL异常
     */
    private String getDatabaseType(Connection connection) throws SQLException {
        return DB_TYPE_CACHE.computeIfAbsent(
                connection.getMetaData().getURL(), // 使用 URL 作为缓存键
                key -> {
                    try {
                        String dbProductName = connection.getMetaData().getDatabaseProductName();
                        log.info("Database product name: " + dbProductName);
                        return dbProductName;
                    } catch (SQLException e) {
                        log.error("Failed to retrieve database product name", e);
                        throw new RuntimeException(e);
                    }
                }
        );
    }

}
